using System;
using System.ComponentModel.Design;
using System.IO;
using EnvDTE;
using EnvDTE80;
using Microsoft.Practices.Common.Services;
using Microsoft.Practices.RecipeFramework;
using Microsoft.Practices.RecipeFramework.Extensions.CommonHelpers;
using VSLangProj;

namespace PrismFactory.SoftwareFactory.Actions
{
    public class UnfoldModuleProjectsAction : ConfigurableAction
    {
        [Input]
        public string ModuleProjectTemplate { get; set; }

        [Input]
        public string ModuleTestProjectTemplate { get; set; }

        [Input]
        public Project InfrastructureProject { get; set; }

        [Input]
        public string RootNamespace { get; set; }

        [Input]
        [Output]
        public Project ModuleProject { get; set; }

        [Output]
        public Project TestProject { get; set; }

        public override void Execute()
        {
            var dte = GetService<DTE>();

            var projectName = RootNamespace + "." + ModuleProject.Name;
            var target = ModuleProject.ParentProjectItem == null ? ModuleProject.DTE.Solution : ModuleProject.ParentProjectItem.ContainingProject.Object;
            var targetDirectory = Path.GetDirectoryName(ModuleProject.FileName);

            // NOTE: Visual Studio always creates:
            // - a project file 
            // - a obj folder
            // - a Properties folder (VB only)
            // before running the wizard. We need to remove those
            // because we want to store the project in a subfolder instead.

            // Remove original (handle and file) project
            string obsoleteProjectPath = ModuleProject.FullName;
            dte.Solution.Remove(ModuleProject);

            if (!string.IsNullOrEmpty(obsoleteProjectPath))
            {
                if (File.Exists(obsoleteProjectPath))
                {
                    File.Delete(obsoleteProjectPath);
                }
                string objFolder = Path.Combine(Path.GetDirectoryName(obsoleteProjectPath), "obj");
                if (Directory.Exists(objFolder))
                {
                    // Visual basic project not always can delete de obj folder
                    try
                    {
                        Directory.Delete(objFolder, true);
                    }
                    catch
                    {
                    }
                }
                string propertiesFolder = Path.Combine(Path.GetDirectoryName(obsoleteProjectPath), "Properties");
                if (Directory.Exists(propertiesFolder))
                {
                    try
                    {
                        Directory.Delete(propertiesFolder, true);
                    }
                    catch
                    {
                    }
                }
            }

            UnfoldTemplateOnTarget(target, ModuleProjectTemplate, targetDirectory, projectName);
            ModuleProject = FindProjectByNameEx(dte, projectName);

            var testProjectName = String.Format("{0}.Tests", ModuleProject.Name);
            UnfoldTemplateOnTarget(target, ModuleTestProjectTemplate, targetDirectory, testProjectName);
            TestProject = DteHelperEx.FindProjectByName(dte, testProjectName, false);

            // Update projects references
            ((VSProject) TestProject.Object).References.AddProject(ModuleProject);
            ((VSProject) ModuleProject.Object).References.AddProject(InfrastructureProject);
        }

        // This method fix the problem with GAX that founds a SolutionFolder as a project
        private Project FindProjectByNameEx(DTE dte, string projectName)
        {
            return DteHelperEx.FindProject(dte, internalProject => internalProject.Name == projectName && !(internalProject.Object is SolutionFolder));
        }

        public override void Undo()
        {
        }


        private void UnfoldTemplateOnTarget(object target, string template, string destination, string name)
        {
            if (target is SolutionFolder)
            {
                ((SolutionFolder) target).AddFromTemplate(ResolveTemplateDirectory(template), Path.Combine(destination, name), name);
            }
            else if (target is Solution)
            {
                ((Solution) target).AddFromTemplate(ResolveTemplateDirectory(template), Path.Combine(destination, name), name, false);
            }
        }

        private string ResolveTemplateDirectory(string template)
        {
            if (!File.Exists(template))
            {
                var typeResService = (TypeResolutionService) GetService(typeof (ITypeResolutionService));
                if (typeResService != null)
                {
                    template = new FileInfo(Path.Combine(
                        typeResService.BasePath + @"\Templates\", template)).FullName;
                }
            }
            return template;
        }
    }
}